package com.koron.standard.deviceClasssify.excel;

import cn.hutool.core.map.BiMap;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.util.ListUtils;
import com.koron.standard.deviceClasssify.bean.excel.TypeParamsExcel;
import com.koron.standard.deviceClasssify.bean.po.Type;
import com.koron.standard.deviceClasssify.bean.po.TypeParams;
import com.koron.standard.deviceClasssify.service.TypeParamsService;
import com.koron.standard.deviceClasssify.service.TypeService;
import com.koron.standard.excel.ExcelError;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author jzp
 * @since 2022/5/11
 */
@Slf4j
public class TypeParamsExcelListener extends AnalysisEventListener<TypeParamsExcel> {
    /**
     * 每隔5条存储数据库，实际使用中可以100条，然后清理list ，方便内存回收
     */
    private static final int BATCH_COUNT = 100;

    private String preTypeId;
    private Integer preRowIndex;

    private final Map<Integer, ExcelError> excelErrors = new HashMap<>();

    /**
     * 缓存的数据
     */
    private List<TypeParams> typeParamsList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

    private final BiMap<String, String> typeMap;
    private final TypeParamsService typeParamsService;

    public TypeParamsExcelListener(TypeService typeService, TypeParamsService typeParamsService) {
        List<Type> list = typeService.list();
        typeMap = new BiMap<>(list.stream().collect(Collectors.toMap(Type::getId, Type::getCode, (o1, o2) -> o1)));
        this.typeParamsService = typeParamsService;
    }

    @Override
    public void invoke(TypeParamsExcel data, AnalysisContext context) {
        Integer rowIndex = context.readRowHolder().getRowIndex();
        // 如果参数名称不为空。则创建技术参数数据
        if (StrUtil.isNotEmpty(data.getParamName())) {
            String code = data.getCode();
            if (StrUtil.isNotEmpty(code)) {
                String typeId = typeMap.getKey(code);
                if (!Objects.equals(typeId, preTypeId)) {
                    preTypeId = typeId;
                    preRowIndex = rowIndex;
                }
                if (StrUtil.isNotEmpty(code) && StrUtil.isEmpty(typeId)) {
                    log.error("分类编码找不到：" + data);
                    ExcelError excelError = new ExcelError(rowIndex, 0, "该分类编码找不到");
                    excelErrors.put(rowIndex, excelError);
                }
            }

            TypeParams typeParams = data.buildParam(preTypeId, rowIndex - preRowIndex);
            typeParamsList.add(typeParams);
            // 达到BATCH_COUNT了，需要去存储一次数据库，防止数据几万条数据在内存，容易OOM
            if (typeParamsList.size() >= BATCH_COUNT) {
                saveParams();
                // 存储完成清理 list
                typeParamsList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
            }
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        saveParams();
        log.info("所有数据解析完成！");
    }

    private void saveParams() {
        if (getExcelErrors().size() == 0) {
            log.info("{}条数据，开始存储数据库！", typeParamsList.size());
            typeParamsService.saveBatch(typeParamsList);
            log.info("存储数据库成功！");
        } else {
            log.error("存在错误，输出错误文件");
        }
    }

    public List<ExcelError> getExcelErrors() {
        return new ArrayList<>(excelErrors.values());
    }

}
